/* 
 * File:   ServerSocket.cpp
 * Author: mauro
 * 
 * Created on 28 de septiembre de 2014, 00:07
 */

#include "ServerSocket.h"

ServerSocket::ServerSocket() {
}

int ServerSocket::initSocket() {
    //creo el socket del server.
    this->server = socket(AF_INET, SOCK_STREAM, 0);
    return this->server;
}
//Informacion sobre la direccion del servidor.
int ServerSocket::initServer(char *ip, int port) {

    this->serverAddress.sin_family = AF_INET;
    this->serverAddress.sin_addr.s_addr = inet_addr(ip);
    this->serverAddress.sin_port = htons(port);
//    ::memset (&(this->serverAddress.sin_zero),'\0',8);
    int len = sizeof (this->serverAddress);
    //en que puerto estoy?
    int estado = bind(this->server, (struct sockaddr*) & this->serverAddress, len);
    return estado;
}

//el servidor espera llamadas (una cola de llamadas).

int ServerSocket::listen(int backLog) {
    int estado = ::listen(this->server, backLog);
    return estado;
}

//para aceptar un cliente.

int ServerSocket::accept(struct sockaddr_in clientAddress) {
    unsigned int leng = sizeof (struct sockaddr_in);
    int clientSocket = ::accept(this->server, (struct sockaddr*) &clientAddress, &leng);

    return clientSocket;
}
//notese que el envio se hace por el socket de communicacion, el socket que se obtiene por 
//accept
//post: devuelve el numero de bytes que se enviaron.

int ServerSocket::send(int socket, void *cad, int length) {
    int estado = ::send(socket, cad, length, 0);
    return estado;
}
//Envia todos los datos.

int ServerSocket::sendAll(int socket, void* buf, int len) {
    int total = 0;
    int bytesLeft = len;
    int n = 0;
    while (total < len) {        
        n = this->send(socket, buf + total, len);        
        if (n == -1) {
            return n;
        }
        total += n;
        bytesLeft -= n;
    }
    return total;
}

int ServerSocket::recvTimeOut(int socket, void* buf, int len, int timeOut) {
    fd_set fds; //Descriptor de fichero.
    int n;
    struct timeval tv; //permite establecer un periodo maximo de espera.    
    FD_ZERO(&fds); //borra un conjunto de descriptores de fichero.    
    FD_SET(socket, &fds); //añade socket al conjunto.
    //Estructura timeval del temporizador
    tv.tv_sec = timeOut; //numero de seg que quiero esperar. 
    
    tv.tv_usec = 0; // numero de microsegundos. (hay 1.000.000 de microseg en un seg)
    //esperar hasta que se reciban datos o venza el temporizador.
    
    n = select(socket + 1, &fds, NULL, NULL, &tv);
    if (n == 0) return -2; //el temporizador ha vencido!
    if (n == -1) return -1; //error
    //los datos deben estar ahí, así que llamo a normalmente a recvAll()
    return this->receiveAll(socket, buf, len);
}
//post: devuelve el numero de bytes que se recibieron.

int ServerSocket::receive(int socket, void *cad, int length) {
    //necesita el socket de donde se va a leer la informacion.      
    int estado = ::recv(socket, cad, length, 0);
    return estado;
}

//recibe todo los datos.
int ServerSocket::receiveAll(int socket, void *buf, int length) {
    int total = 0;
    int bytesLeft = length;
    int cant = 0;
    while (total < length) {                
        cant = this->receive(socket, buf + total, length);        
        if (cant == -1) {
            break;
        }
        if (cant == 0){
            return 0;
        }        
        total += cant;
        bytesLeft -= cant;
    }
    return total;
}

int ServerSocket::getSocket() {
    return this->server;
}

void ServerSocket::close() {
    //    this->client = -1;
    shutdown(this->server, 2);
    ::close(this->server);
    //    this->server = -1;

}

ServerSocket::~ServerSocket() {
}

